import {
  document,
	window,
	HTMLCanvasElement,
	requestAnimationFrame,
	cancelAnimationFrame,
core,
	Event,
  Event0
} from "dhtml-weixin"
import * as THREE from './three/Three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { OrbitControls0 } from 'three/addons/controls/OrbitControls0.js';
var requestId
Page({
  onShareAppMessage(){
    return getApp().onShare()
  },
  onShareTimeline(){
     return {title:"ThreeX 2.0"}
  },
	onUnload() {
		cancelAnimationFrame(requestId, this.canvas)
		this.worker && this.worker.terminate()
if(this.canvas) this.canvas = null
		setTimeout(() => {
			if (this.renderer instanceof THREE.WebGLRenderer) {
				this.renderer.dispose()
				this.renderer.forceContextLoss()
				this.renderer.context = null
				this.renderer.domElement = null
				this.renderer = null
			}
		}, 0)
	},
  webgl_touch(e){
		const web_e = (window.platform=="devtools"?Event:Event0).fix(e)
		this.canvas.dispatchEvent(web_e)
  },
  onLoad() {
		document.createElementAsync("canvas", "webgl2").then(canvas => {
      this.canvas = canvas
      this.body_load(canvas).then()
    })
  },
  async body_load(canvas3d) {

    let container;
    let camera, scene, renderer;

    const CubemapFilterShader = {
      uniforms: {
        cubeTexture: { value: null },
        mipIndex: { value: 0 },
      },

      vertexShader: /* glsl */ `

        varying vec3 vWorldDirection;

        #include <common>

        void main() {
          vWorldDirection = transformDirection(position, modelMatrix);
          #include <begin_vertex>
          #include <project_vertex>
          gl_Position.z = gl_Position.w; // set z to camera.far
        }

        `,

      fragmentShader: /* glsl */ `

        uniform samplerCube cubeTexture;
        varying vec3 vWorldDirection;

        uniform float mipIndex;

        #include <common>

        void main() {
          vec3 cubeCoordinates = normalize(vWorldDirection);

          // Colorize mip levels
          vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
          if (mipIndex == 0.0) color.rgb = vec3(1.0, 1.0, 1.0);
          else if (mipIndex == 1.0) color.rgb = vec3(0.0, 0.0, 1.0);
          else if (mipIndex == 2.0) color.rgb = vec3(0.0, 1.0, 1.0);
          else if (mipIndex == 3.0) color.rgb = vec3(0.0, 1.0, 0.0);
          else if (mipIndex == 4.0) color.rgb = vec3(1.0, 1.0, 0.0);

          gl_FragColor = textureCube(cubeTexture, cubeCoordinates, 0.0) * color;
        }

        `,
    };


    init();
    animate();


    async function loadCubeTexture( urls ) {

      return new Promise( function ( resolve ) {

        new THREE.CubeTextureLoader().load( urls, function ( cubeTexture ) {

          resolve( cubeTexture );

        } );


      } );

    }

    function allocateCubemapRenderTarget( cubeMapSize ) {

      const params = {
        magFilter: THREE.LinearFilter,
        minFilter: THREE.LinearMipMapLinearFilter,
        generateMipmaps: false,
        type: THREE.HalfFloatType,
        format: THREE.RGBAFormat,
        colorSpace: THREE.LinearSRGBColorSpace,
        depthBuffer: false,
      };

      const rt = new THREE.WebGLCubeRenderTarget( cubeMapSize, params );

      const mipLevels = Math.log( cubeMapSize ) * Math.LOG2E + 1.0;
      for ( let i = 0; i < mipLevels; i ++ ) rt.texture.mipmaps.push( {} );

      rt.texture.mapping = THREE.CubeReflectionMapping;
      return rt;

    }

    function renderToCubeTexture( cubeMapRenderTarget, sourceCubeTexture ) {

      const geometry = new THREE.BoxGeometry( 5, 5, 5 );

      const material = new THREE.ShaderMaterial( {
        name: 'FilterCubemap',
        uniforms: THREE.UniformsUtils.clone( CubemapFilterShader.uniforms ),
        vertexShader: CubemapFilterShader.vertexShader,
        fragmentShader: CubemapFilterShader.fragmentShader,
        side: THREE.BackSide,
        blending: THREE.NoBlending,
      } );

      material.uniforms.cubeTexture.value = sourceCubeTexture;

      const mesh = new THREE.Mesh( geometry, material );
      const cubeCamera = new THREE.CubeCamera( 1, 10, cubeMapRenderTarget );
      const mipmapCount = Math.floor( Math.log2( Math.max( cubeMapRenderTarget.width, cubeMapRenderTarget.height ) ) );

      for ( let mipmap = 0; mipmap < mipmapCount; mipmap ++ ) {

        material.uniforms.mipIndex.value = mipmap;
        material.needsUpdate = true;

        cubeMapRenderTarget.viewport.set( 0, 0, cubeMapRenderTarget.width >> mipmap, cubeMapRenderTarget.height >> mipmap );

        cubeCamera.activeMipmapLevel = mipmap;
        cubeCamera.update( renderer, mesh );

      }

      mesh.geometry.dispose();
      mesh.material.dispose();

    }

    function init() {

      container = document.createElement( 'div' );
      document.body.appendChild( container );

      // Create renderer
      renderer = new THREE.WebGLRenderer( { antialias: true } );
      renderer.setPixelRatio( window.devicePixelRatio );
      renderer.setSize( window.innerWidth, window.innerHeight );
      container.appendChild( renderer.domElement );

      scene = new THREE.Scene();

      camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10000 );
      camera.position.z = 500;

      // Create controls
      const controls = new (window.platform=="devtools"?OrbitControls:OrbitControls0)( camera, renderer.domElement );
      controls.minPolarAngle = Math.PI / 4;
      controls.maxPolarAngle = Math.PI / 1.5;

      window.addEventListener( 'resize', onWindowResize );

      // Load a cube texture
      const r = 'textures/cube/Park3Med/';
      const urls = [
        r + 'px.jpg', r + 'nx.jpg',
        r + 'py.jpg', r + 'ny.jpg',
        r + 'pz.jpg', r + 'nz.jpg'
      ];

      loadCubeTexture( urls ).then( ( cubeTexture ) => {

        // Allocate a cube map render target
        const cubeMapRenderTarget = allocateCubemapRenderTarget( 512 );

        // Render to all the mip levels of cubeMapRenderTarget
        renderToCubeTexture( cubeMapRenderTarget, cubeTexture );

        // Create geometry
        const sphere = new THREE.SphereGeometry( 100, 128, 128 );
        let material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: cubeTexture } );

        let mesh = new THREE.Mesh( sphere, material );
        mesh.position.set( - 100, 0, 0 );
        scene.add( mesh );

        material = material.clone();
        material.envMap = cubeMapRenderTarget.texture;

        mesh = new THREE.Mesh( sphere, material );
        mesh.position.set( 100, 0, 0 );
        scene.add( mesh );

      } );

    }

    function onWindowResize() {

      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();

      renderer.setSize( window.innerWidth, window.innerHeight );

    }

    function animate() {

      requestId = requestAnimationFrame( animate );
      renderer.render( scene, camera );

    }
  }
})